﻿//***********************************************************************************************************************
//
//文件名(File Name):     IminectPlayerInfo .cs
using UnityEngine;
using System;
using System.Threading;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;
using IMIForUnity;

namespace IMIForUnity
{

    public class ImiManager : MonoBehaviour, IManager
    {

        private static ImiManager instance = null;
        private static ImiManagerImp imiManagerImp = null;
        private static MainThreadDispatcher mainThreadDispatcher = null;

        /// <summary>
        /// 是否开启性能模式（性能模式下支持720P，但是无法使用彩色抠图）
        /// </summary>
        public bool IsPerformance = false;

        /// <summary>
        /// 彩色图
        /// </summary>
        public bool ColorTexture = false;
        /// <summary>
        /// 深度图（不含玩家标识、玩家抠图）
        /// </summary>
        public bool DepthTexture = false;
        /// <summary>
        /// 骨骼数据
        /// </summary>
        public bool SkeletonData = false;
        /// <summary>
        /// 深度图、玩家深度抠图
        /// </summary>
        public bool UserDepthTexture = false;
        /// <summary>
        /// 玩家彩色抠图
        /// </summary>
        public bool UserColorTexture = false;


        /// <summary>
        /// 是否自动启动
        /// </summary>
        public bool StartAutomatically = true;

        /// <summary>
        /// 是否自动升级
        /// </summary>
        public bool AutoUpgrade = false;

        /// <summary>
        /// 是否显示深度图细节（性能消耗）
        /// </summary>
        public bool ShowDepthDetail = false;

        /// <summary>
        /// 是否使用root权限
        /// </summary>
        public bool useRootPermission = false;


        public ImiResolution.Type imageResolution = ImiResolution.Type._640x480;
        public ImiResolution.Type depthResolution = ImiResolution.Type._640x480;

        public delegate void DeviceOpened();
        public delegate void DeviceClosed();
        public delegate void DeviceConnected();
        public delegate void DeviceDisconnected();

        public DeviceOpened OnDeviceOpened;
        public DeviceClosed OnDeviceClosed;
        public DeviceConnected OnDeviceConnected;
        public DeviceDisconnected OnDeviceDisconnected;

        /// <summary>
        /// Callback when Control Player has changed 
        /// </summary>
        /// <param name="code"></param>
        public delegate void OnControlPlayerChanged(int oldControleId, int newControlId);

        public delegate void OnPlayerEntered(int playerId);

        public delegate void OnPlayerLost(int playerId);

        public delegate void DepthDataProcessor(ushort[] depthData);

        public delegate void ColorDataProcessor(byte[] colorData);

        public delegate void RawDataProcessor(byte[] colorData,ushort[] depthData);

        public ImiGestureManager gestureManager;

        private bool isPaused;

        public static ImiManager GetInstance()
        {
            if (!Exists())
            {
                //return null;
                throw new Exception("Could not find the ImiManager object. Please ensure you have added the ImiManager Prefab to your scene.");
            }
            return instance;
        }

        private ImiManager() { }

        void Awake()
        {
            if (instance == null)
            {
                instance = this;
                imiManagerImp = ImiManagerImp.GetInstance();
                mainThreadDispatcher = MainThreadDispatcher.GetInstance();
                DontDestroyOnLoad(this.gameObject);

                gestureManager = ImiGestureManager.GetInstance();

                //Keep Screen On!
                Screen.sleepTimeout = SleepTimeout.NeverSleep;
            }
        }
        void Start()
        {
            if (StartAutomatically)
            {
                OpenDevice();
            }
        }

        public void Update()
        {
            if (mainThreadDispatcher != null)
            {
                mainThreadDispatcher.update();
            }
            if (imiManagerImp != null)
                {
                    imiManagerImp.Update();
                }

            //Check Device State constantly to support Hot swap
#if UNITY_ANDROID && !UNITY_EDITOR
            //imiManagerImp.CheckDeviceState();
#endif
        }

        void OnApplicationQuit()
        {
            Debug.Log("ImiUnityLog : Enter OnApplicationQuit");
            if (IsDeviceWorking())
            {
                CloseDevice();
            }

            instance = null;
        }

        void OnApplicationPause(bool pauseStatus)
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            Debug.Log("ImiUnityLog : Enter OnApplicationPause");
            if (IsDeviceWorking())
            {
                Debug.Log("ImiUnityLog : Enter OnApplicationPause, device is working");
                CloseDevice();
                instance = null;
                // 退出应用
                Application.Quit();
            }
#endif
        }

        /// <summary>
        /// If instance Exists
        /// </summary>
        /// <returns></returns>
        private static bool Exists()
        {
            //User Reference Equals To Avoid CompareBaseObjectsInternal error
            return !ReferenceEquals(instance, null);
        }


        /// <summary>
        /// Check if the device is opened and ready to use
        /// </summary>
        /// <returns></returns>
        public bool IsDeviceWorking()
        {
            if (imiManagerImp != null)
                return imiManagerImp.IsDeviceWorking();
            else
                return false;
        }

        internal void _OnDeviceOpened()
        {
            if (IsDeviceWorking())
            {
                if (OnDeviceOpened != null)
                {
                    mainThreadDispatcher.Enqueue(() => {
                        if(OnDeviceOpened!= null)
                        {
                            OnDeviceOpened.Invoke();
                        }
                    });
                }
            }
        }

        internal void _OnDeviceClosed()
        {
            if (!IsDeviceWorking())
            {
                if (OnDeviceClosed != null)
                {
                    mainThreadDispatcher.Enqueue(() => {
                        if(OnDeviceClosed != null)
                        {
                            OnDeviceClosed.Invoke();
                        }
                    });
                }
            }
        }

        internal void _OnDeviceConnected()
        {
            if (OnDeviceConnected != null)
            {
                mainThreadDispatcher.Enqueue(() => {
                    if (OnDeviceConnected != null)
                    {
                        OnDeviceConnected.Invoke();
                    }
                });

            }

        }

        internal void _OnDeviceDisconnected()
        {
            if (OnDeviceDisconnected != null)
            {
                mainThreadDispatcher.Enqueue(()=> {
                    if(OnDeviceDisconnected != null)
                    {
                        OnDeviceDisconnected.Invoke();
                    }
                });
            }

        }

        /// <summary>
        /// Open Device and Open Default Streams
        /// </summary>
        public void OpenDevice()
        {
            if (IsDeviceWorking())
            {
                Debug.Log("Device Has Already Opened! Don't Open Again!");
                _OnDeviceOpened();
                return;
            }
            imiManagerImp.Open();
        }


        /// <summary>
        /// Open Device and specific streams
        /// </summary>
        /// <param name="openDepthTexture"></param>
        /// <param name="openSkeletonData"></param>
        /// <param name="openUserDepthTexture"></param>
        /// <param name="openColorTexture"></param>
        public void OpenDevice(bool openDepthTexture, bool openSkeletonData, bool openUserDepthTexture, bool openColorTexture)
        {
            this.DepthTexture = openDepthTexture;
            this.SkeletonData = openSkeletonData;
            this.UserDepthTexture = openUserDepthTexture;
            this.ColorTexture = openColorTexture;
            OpenDevice();
        }

        /// <summary>
        /// Open Device With User Color Texture
        /// Note: This Option cannot use with color Texture/ user depth texture the same time!
        /// </summary>
        /// <param name="openUserColorTexture"></param>
        public void OpenDevice(bool openUserColorTexture)
        {
            if (openUserColorTexture)
            {
                this.DepthTexture = false;
                this.SkeletonData = false;
                this.UserDepthTexture = false;
                this.ColorTexture = false;
                this.UserColorTexture = true;
            }
            OpenDevice();
        }

        /// <summary>
        /// 打开默认流
        /// </summary>
        public void OpenStream()
        {
            imiManagerImp.OpenStream();
        }

        /// <summary>
        /// 重新打开指定流
        /// </summary>
        /// <param name="openDepthTexture">需要深度图</param>
        /// <param name="openSkeletonData">需要骨骼数据</param>
        /// <param name="openUserDepthTexture">需要包含用户ID的深度图（可以来标识用户）</param>
        /// <param name="openColorTexture">需要彩色图</param>
        public void OpenStream(bool openDepthTexture, bool openSkeletonData, bool openUserDepthTexture, bool openColorTexture)
        {
            this.DepthTexture = openDepthTexture;
            this.SkeletonData = openSkeletonData;
            this.UserDepthTexture = openUserDepthTexture;
            this.ColorTexture = openColorTexture;
            OpenDevice();
 
        }

        /// <summary>
        /// 打开可用于彩色抠图的流
        /// 彩色抠图无法与彩色图、深度图同时使用,因此打开该方法会覆盖其他流，只能获取彩色抠图
        /// </summary>
        /// <param name="openUserColorTexture"></param>
        public void OpenStream(bool openUserColorTexture)
        {
            if (openUserColorTexture)
            {
                this.DepthTexture = false;
                this.SkeletonData = false;
                this.UserDepthTexture = false;
                this.ColorTexture = false;
                this.UserColorTexture = true;
            }
            OpenStream();
 
        }

        /// <summary>
        /// 关闭相应流
        /// </summary>
        public void CloseStream()
        {
            imiManagerImp.CloseStream();
        }

        public ImiDevice GetDevice()
        {
            return null;
        }


        /// <summary>
        /// 关闭设备
        /// </summary>
        public void CloseDevice()
        {
            imiManagerImp.Close();
            if (OnDeviceClosed != null)
            {
                OnDeviceClosed.Invoke();
            }
        }


        public ImiResolution GetColorResolution()
        {
            return imiManagerImp.GetColorResolution();
        }

        public ImiResolution GetDepthResolution()
        {
            return imiManagerImp.GetDepthResolution();
        }

        /// <summary>
        /// 获取颜色图像.
        /// </summary>
        /// <returns></returns>
        public Texture2D GetColorTexture()
        {
            return imiManagerImp.GetColorTexture();
        }

        public Texture2D GetMainUserColorTexture()
        {
            return imiManagerImp.GetMainUserColorTexture();
        }

        public Texture2D GetSubUserColorTexture()
        {
            return imiManagerImp.GetSubUserColorTexture();
        }

        public Texture2D GetDepthTexture()
        {
            return imiManagerImp.GetDepthTexture();
        }

        /// <summary>
        /// 获取包含玩家的深度图像.
        /// </summary>
        /// <returns></returns>
        public Texture2D GetUserDepthTexture()
        {
            return imiManagerImp.GetUserDepthTexture();
        }

        /// <summary>
        /// 获得主要玩家深度图信息
        /// </summary>
        /// <returns>主要玩家深度图</returns>
        public Texture2D GetMainUserDepthTexture()
        {
            return imiManagerImp.GetMainUserDepthTexture();
        }

        //public void AddGestures(IminectGestures.Gestures gesture)
        //{
        //    imiManagerImp.AddGesture(gesture);
        //}

        /// <summary>
        /// 获得第二个玩家的深度图信息
        /// </summary>
        /// <returns>第二个玩家深度图</returns>
        public Texture2D GetSubUserDepthTexture()
        {
            return imiManagerImp.GetSubUserDepthTexture();
        }

        /// <summary>
        /// 获取用户信息. 用户信息包含了骨骼信息.
        /// </summary>
        /// <returns></returns>
        public Dictionary<int, ImiPlayerInfo> GetPlayerInfos()
        {
            return imiManagerImp.playerInfos;
        }

        /// <summary>
        /// 根据Id获取用户信息
        /// </summary>
        /// <param name="userIndex">用户Id</param>
        /// <returns></returns>
        public ImiPlayerInfo GetPlayerInfo(int userIndex)
        {
            return imiManagerImp.GetPlayerInfo(userIndex);
        }

        public ImiPlayerInfo GetMainPlayerInfo()
        {
            return imiManagerImp.GetMainPlayerInfo();
        }

        public ImiPlayerInfo GetSubPlayerInfo()
        {
            return imiManagerImp.GetSubPlayerInfo();
        }

        /// <summary>
        /// 设置控制玩家ID.
        /// </summary>
        /// <param name="index"></param>
        public void SetControlPlayerId(int userId)
        {
            imiManagerImp.SetControlPlayerId(userId);
        }

        /// <summary>
        /// 设置副控玩家ID
        /// </summary>
        /// <param name="userId"></param>
        public void SetSubControlPlayerId(int userId)
        {
            imiManagerImp.SetSubControlPlayerId(userId);
        }
 

        public void SetPlayerControlMode(PlayerControlMode mode)
        {
            imiManagerImp.SetPlayerControlMode(mode);
        }

        public PlayerControlMode GetPlayerControlMode()
        {
            return imiManagerImp.GetPlayerControlMode();
        }

        /// <summary>
        /// 设置跟踪玩家的模式（最近或者挥手）
        /// </summary>
        /// <param name="mode"></param>
        public void SetUserTrackingMode(UserTrackingMode mode)
        {

        }
        
        public Texture2D GetMainUserColorTextureInCenter()
        {
            return imiManagerImp.GetMainUserColorTextureInCenter();
        }

        public Texture2D GetSubUserColorTextureInCenter()
        {
            return imiManagerImp.GetSubUserColorTextureInCenter();
        }

        /// <summary>
        /// 设置跟踪的UserId
        /// </summary>
        /// <param name="userId">玩家的id</param>
        /// <returns>跟踪成功或者失败</returns>
        public bool SetTrackingUserId(int userId)
        {
            return imiManagerImp.SetTrackingUserId(userId);
        }

        /// <summary>
        /// 设置跟踪的UserId
        /// </summary>
        /// <param name="userId">玩家的id</param>
        /// <returns>跟踪成功或者失败</returns>
        public bool SetUnTrackingUserId(int userId)
        {
            return imiManagerImp.SetUnTrackingUserId(userId);
        }


        public int GetControlPlayerId()
        {
            return imiManagerImp.GetControlPlayerId();
        }

        public int GetSubPlayerId()
        {
            return imiManagerImp.GetSubPlayerId();
        }

        public void SetDepthDataProcessor(DepthDataProcessor processor)
        {
            imiManagerImp.SetDepthDataProcessor(processor);
        }

        public void SetColorDataProcessor(ColorDataProcessor processor)
        {
             imiManagerImp.SetColorDataProcessor(processor);
        }

        public void SetRawDataProcessor(RawDataProcessor processor)
        {
             imiManagerImp.SetRawDataProcessor(processor);
        }

        public void SetControlPlayerChangeListener(OnControlPlayerChanged observer)
        {
            imiManagerImp.SetControlPlayerChangeListener(observer);
        }

        public void SetPlayerEnteredListener(OnPlayerEntered observer)
        {
            imiManagerImp.SetPlayerEnteredListener(observer);
        }

        public void SetPlayerLostListener(OnPlayerLost observer)
        {
            imiManagerImp.SetPlayerLostListener(observer);
        }



        public Texture2D GetColorTexture(int userId)
        {
            return null;
        }

        public Texture2D GetColorTexture(List<int> ids)
        {
            return null;
        }

        public Texture2D GetUserDepthTexture(int userId)
        {
            return null;
        }

        public Texture2D GetUserColorTextureInCenter(int userId)
        {
            return null;
        }



        public Texture2D GetUserDepthTexture(List<int> userId)
        {
            return null;
        }

        public Vector3[] GetNormalizedSkeleton(int userIndex)
        {
            return imiManagerImp.GetNormalizedSkeleton(userIndex);
        }

        public Texture2D GetColorTextureInCenter(int userIndex)
        {
            return imiManagerImp.GetColorTextureInCenter(userIndex);
        }

        public ImiDeviceInfo GetDeviceInfo()
        {
            return imiManagerImp.GetDeviceInfo();
        }

    }
}
